package com.huawei.fakedouyin.danmu;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

import com.huawei.fakedouyin.util.LogUtilKt;
import com.huawei.fakedouyin.util.SPUtil;
import com.huawei.faketaobao.constant.IConstant;
import com.huawei.faketaobao.constant.SPConstant;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.UUID;

/**
 * 弹幕view
 */
public class DMSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    //用于标注线程是否继续
    private boolean Flag = false;

    private String TAG = "DMSurfaceView";

    //SurfaceHolder
    SurfaceHolder surfaceHolder;

    //每次移动多少距离
    public int moveSpeed = 5;
    //透明度
    public int textApl = 255;

    //文字缩放大小
    private float textSizeChange = 1f;

    //是否暂停
    private boolean pause = false;

    //存放高等级弹幕待添加的列表
    LinkedHashSet<TextBean> beanHashSet = new LinkedHashSet<>();
    Canvas canvas = null;
    TextBean mText = null;
    Paint paint = new Paint();
    //一行文字的高度  动态计算
    private float textHeight = 40;

    //单个文字的宽度 动态计算
    private float textWidth = 40;
    //最大通道
    private int maxLevel = IConstant.defaultLevel;

    //每个弹幕的最短间隔距离  过短时:切换字体大小会导致弹幕重叠  可动态计算(当前计算方式为 上个弹幕的所占屏幕长度 / 2)
    private int minDistance = 250;

    private Thread thread;

    private boolean isInit = false;

    //在播放弹幕的集合  所有在屏幕上正在绘制的弹幕
    public List<TextBean> Barrages = new ArrayList<>();
    //所有通道的弹幕集合 allList的size就是总通道数
    public List<List<TextBean>> allList = new ArrayList<>();

    //弹幕总开关
    private boolean danmuSwitch = true;

    //是否有间隙
    private boolean hasSpace = true;


    public DMSurfaceView(Context context) {
        super(context);
    }

    public DMSurfaceView(Context context, AttributeSet attrs) {
        super(context, attrs);

        surfaceHolder = getHolder();
        surfaceHolder.addCallback(this);

        //设置背景透明
        this.setZOrderOnTop(true);
        surfaceHolder.setFormat(PixelFormat.TRANSLUCENT);
        init();
    }


    public DMSurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        LogUtilKt.logDebug("surfaceCreated");
        Flag = true;
        //启动线程绘制
        thread = new Thread(this);
        thread.start();

    }

//    public void setPause(boolean pause) {
//        this.pause = pause;
//    }

    public void onPause() {
        pause = true;
        Log.d(TAG, "onPause pause:" + pause);
    }

    public void onResume() {
        pause = false;
        Log.d(TAG, "onResume pause:" + pause);
    }

    private void init() {
        refreshSwitch();
        //字体缩放大小
        refreshTextSizeChange();
        //初始化数据
        for (int i = 0; i < 4; i++) {
            allList.add(new ArrayList<>());
        }
        //等待allList初始化完成后再初始化
        refreshMaxLevel();
        refreshMoveSpeed();
        refreshApl();
        isInit = true;
        setLayerType(LAYER_TYPE_HARDWARE, null);

    }

    /**
     * 刷新字体缩放大小
     */
    public void refreshTextSizeChange() {
        textSizeChange = Float.parseFloat(SPUtil.Companion.getInstance().getString(SPConstant.textSizeChange, IConstant.textSizeChange + ""));
    }

    /**
     * 刷新最大通道数
     */
    public void refreshMaxLevel() {
        maxLevel = SPUtil.Companion.getInstance().getInt(SPConstant.maxLevel, IConstant.defaultLevel);
        //清除历史数据
        for (int i = allList.size() - 1; i > maxLevel; i--) {
            allList.get(i).clear();
        }
    }

    /**
     * 设置透明度 0-255
     *
     * @param apl
     */
    public void setTextApl(int apl) {
        this.textApl = apl;
    }

    /**
     * 刷新透明度
     */
    public void refreshApl() {
        textApl = SPUtil.Companion.getInstance().getInt(SPConstant.danmuAlpha, IConstant.textApl) + IConstant.textBaseApl;
    }

    /**
     * 刷新弹幕开关状态
     */
    public void refreshSwitch() {
        danmuSwitch = SPUtil.Companion.getInstance().getBoolean(SPConstant.danmuSwitch, IConstant.danmuSwitch);
    }

    /**
     * 刷新移动速度
     */
    public void refreshMoveSpeed() {
        moveSpeed = SPUtil.Companion.getInstance().getInt(SPConstant.moveSpeed, IConstant.moveSpeed);
    }

    //添加弹幕
    @SuppressLint("SuspiciousIndentation")
    public boolean add(TextBean bean) {
        boolean success = false;
        //设置x坐标
        bean.setX(getWidth());

        if (bean.getTag().isEmpty()) {
            //通过uuid增加辨识 不会添加重复
            bean.setTag(UUID.randomUUID().toString().replace("-", ""));
        }
        //高等级弹幕
        if (bean.getHighLevel() > 0) {
            beanHashSet.add(bean);
        }

        if (!Flag || pause || !isInit) return success;
        //添加弹幕  按照开放的通道添加
        for (int i = 0; i < maxLevel; i++) {
            //还未添加弹幕就直接添加 无需判断
            if (allList.get(i).size() > 0) {
                //获取最后一个item 根据每个通道的最后一个弹幕绘制的距离 判断是否有间隙插入弹幕
                TextBean temp = allList.get(i).get(allList.get(i).size() - 1);
                //动态计算最短间隔 根据上个文本的最大缩放距离
                minDistance = (int) ((textWidth / 2) * temp.getText().length());
                //是否有间隙 最后一个弹幕和屏幕右侧的距离 大于 (一个文字的宽度 * 该弹幕的文字数量) + 最短间隔
                if (getWidth() - temp.getX() > ((textWidth * temp.getText().length()) + minDistance)) {
                    success = true;
                    if (beanHashSet.size() > 0) {
                        //有高级弹幕待添加  先添加高级弹幕
                        TextBean tempTextBean = getHashBean();
                        boolean isContinue = true;
                        if (tempTextBean.getTag().equals(bean.getTag())) {
                            isContinue = false;
                        }
                        addItem(tempTextBean, i);
                        if (isContinue) {
                            continue;
                        }
                    } else {
                        addItem(bean, i);
                    }
                    break;
                }
            } else {
                success = true;
                if (beanHashSet.size() > 0) {
                    //有高级弹幕待添加  先添加高级弹幕
                    TextBean tempTextBean = getHashBean();
                    boolean isContinue = true;
                    //防止是自己主动添加自己 导致无限循环
                    if (tempTextBean.getTag().equals(bean.getTag())) {
                        isContinue = false;
                    }
                    addItem(tempTextBean, i);
                    if (isContinue) {
                        continue;
                    }
                } else {
                    addItem(bean, i);
                }
                break;
            }
        }

        Log.d(TAG, bean.getText() + "添加成功:" + success + "--添加 高级弹幕:" + (bean.getHighLevel() > 0) + " 失败是否丢弃:" + (bean.getHighLevel() == 0));

//        //存在高级弹幕没完成添加  循环查找间隙添加
//        if (beanHashSet.size() > 0) {
//            new Handler().postDelayed(new Runnable() {
//                @Override
//                public void run() {
//                    add(getHashBean());
//                }
//            }, 500);
//        }

        return bean.getHighLevel() > 0 ? true : success;
    }

    /**
     * 真正添加item
     */
    private void addItem(TextBean bean, int i) {
        bean.setLevel(i + 1);
        allList.get(i).add(bean);
        //添加成功后remove掉
        if (bean.getHighLevel() > 0) {
            beanHashSet.remove(bean);
        }
    }

    /**
     * 获取高级弹幕的第一个弹幕
     *
     * @return
     */
    private TextBean getHashBean() {
        TextBean bean = null;
        Iterator iterator = beanHashSet.iterator();
        while (iterator.hasNext()) {
            Object next = iterator.next();
            bean = (TextBean) next;
            break;
        }

        return bean;
    }

    /**
     * 清空已添加和绘制的弹幕
     */
    public void finishAndClean() {

        for (int i = 0; i < allList.size(); i++) {
            allList.get(i).clear();
        }
        beanHashSet.clear();
        Barrages.clear();

    }


    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
        LogUtilKt.logDebug("surfaceChanged");
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        LogUtilKt.logDebug("surfaceDestroyed");
        boolean retry = true;
        while (retry) {
            try {
                //等待结束线程
                Flag = false;
                //主线程等待thread执行完毕，主线程暂时阻塞。thread执行完毕销毁后会唤醒主线程停止阻塞
                thread.join();
                retry = false;
            } catch (InterruptedException e) {
                //e.printStackTrace();
                // 如果线程无法正常结束，则继续重试
            }
        }
    }


    /**
     * 绘制弹幕的线程
     */
    @Override
    public void run() {

        while (Flag) {

            if (!isInit) {
                continue;
            }

            if (!danmuSwitch) {
                //关闭弹幕时清空数据 开启弹幕后开始添加数据
                finishAndClean();
            } else {
                //装填数据
                setDrawData();
            }
            //计算绘制时间
            long startTime = System.currentTimeMillis();
            try {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                    //开启硬件加速 gpu绘制
                    canvas = surfaceHolder.lockHardwareCanvas();
                } else {
                    //cpu绘制
                    canvas = surfaceHolder.lockCanvas();
                }
                //加锁
                synchronized (surfaceHolder) {
                    //清空画布
                    canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
                    //开启弹幕时 绘制
                    if (danmuSwitch) {
                        draw();
                    }
                }
            } catch (Exception e) {

            } finally {
                if (canvas != null) {
                    //解锁画布
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }

            //需要计算绘制所需的时间，并休眠一段时间以维持一定的帧率
            long endTime = System.currentTimeMillis();
            long timeDiff = endTime - startTime;
            //每次绘制间隔时间的控制:休眠时间和绘制时间加一起不超过16毫秒 否则看起来卡顿
            long sleepTime = 16 - timeDiff;
            try {
                if (sleepTime > 0) {
//                    Log.d(TAG, "SurfaceViewSinFun.drawSomething sleepTime=" + sleepTime);
                    Thread.sleep(sleepTime);
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    /**
     * 装填要绘制的弹幕数据
     */
    private void setDrawData() {
        Barrages.clear();
        for (int i = 0; i < maxLevel; i++) {
            Barrages.addAll(allList.get(i));
        }
    }

    /**
     * 绘制屏幕上的的弹幕
     */
    private void draw() {
        paint.setStrokeWidth(3f);
        //抗锯齿
        paint.setAntiAlias(true);
        //最大的字体 * 当前设置的字体大小获取字体高度
        paint.setTextSize(IConstant.textSizeBig * textSizeChange);
        Paint.FontMetrics fontMetrics = paint.getFontMetrics();
        //字体高度
        textHeight = fontMetrics.bottom - fontMetrics.top;
        //一个的字体宽度
        textWidth = paint.measureText("测");
        //遍历弹幕集合
        for (int i = 0; i < Barrages.size(); i++) {
            mText = Barrages.get(i);
            //如果弹幕类中的画笔为空,则在此处定义画笔，根据弹幕类中的颜色大小等进行绘制
            if (paint == null) {
                paint = new Paint();
            }
            paint.setColor(mText.getColor());
            paint.setAlpha(textApl);
            //字体默认大小 * 缩放大小
            paint.setTextSize((mText.getSize() ? IConstant.textSizeBig : IConstant.textSizeSmall) * textSizeChange);

            //绘制文本
            canvas.drawText(mText.getText(), mText.getX(), (textHeight * mText.getLevel()), paint);
            //如果弹幕超出屏幕左侧，则从集合中删除，否则进行移动
            if (mText.getX() <= -(mText.getText().length() * textWidth)) {
                Barrages.remove(mText);
                allList.get(mText.getLevel() - 1).remove(mText);
                i--;
            } else {
                //暂停中可以刷新ui 但是不移动
                mText.setX((mText.getX() - (pause ? 0 : moveSpeed)));
            }

        }
    }

}
